
#include <float.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include "ctypes.h"
#include "cpair.h"

#pragma warning( disable:4996 )

void StlcCopyMemory( void* a_pDest, const void* a_pSrc, size_t a_szCount )
{
	assert( NULL != a_pDest && NULL != a_pSrc && a_szCount > 0 );
	memcpy( a_pDest, a_pSrc, a_szCount );
}

int StlcCompareMemory( const void* a_pLeft, const void* a_pRight, size_t a_szCount )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return memcmp( a_pLeft, a_pRight, a_szCount );
}

int StlcCompareChar( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(char*)a_pLeft <= *(char*)a_pRight ? *(char*)a_pLeft == *(char*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareUnsignedChar( const void* a_pLeft, const void* a_pRight )
{	
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(unsigned char*)a_pLeft <= *(unsigned char*)a_pRight ? *(unsigned char*)a_pLeft == *(unsigned char*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareShort( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(short*)a_pLeft <= *(short*)a_pRight ? *(short*)a_pLeft == *(short*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareUnsignedShort( const void* a_pLeft, const void* a_pRight )
{	
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(unsigned short*)a_pLeft <= *(unsigned short*)a_pRight ? *(unsigned short*)a_pLeft == *(unsigned short*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareInt( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(int*)a_pLeft <= *(int*)a_pRight ? *(int*)a_pLeft == *(int*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareUnsignedInt( const void* a_pLeft, const void* a_pRight )
{	
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(unsigned int*)a_pLeft <= *(unsigned int*)a_pRight ? *(unsigned int*)a_pLeft == *(unsigned int*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareLong( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(long*)a_pLeft <= *(long*)a_pRight ? *(long*)a_pLeft == *(long*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareUnsignedLong( const void* a_pLeft, const void* a_pRight )
{	
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(unsigned long*)a_pLeft <= *(unsigned long*)a_pRight ? *(unsigned long*)a_pLeft == *(unsigned long*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareFloat( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(float*)a_pLeft <= *(float*)a_pRight ? *(float*)a_pLeft == *(float*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareDouble( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return *(double*)a_pLeft <= *(double*)a_pRight ? *(double*)a_pLeft == *(double*)a_pRight ? 0 : -1 : 1;
}

int StlcCompareStringA( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return strcmp( (char*)a_pLeft, (char*)a_pRight );
}

int StlcCompareStringW( const void* a_pLeft, const void* a_pRight )
{
	assert( NULL != a_pLeft && NULL != a_pRight );
	return wcscmp( (wchar_t*)a_pLeft, (wchar_t*)a_pRight );
}

int StlcComparePair( const void* a_pLeft, const void* a_pRight )
{
	PSPair pstLeft  = (PSPair)a_pLeft;
	PSPair pstRight = (PSPair)a_pRight;
	assert( NULL != a_pLeft && NULL != a_pRight );	

	assert( StlcPairSameType( pstLeft, pstRight ) && NULL != pstLeft->pfnFirstCompare );
	return (pstLeft->pfnFirstCompare)( pstLeft->first, pstRight->first );
}

void StlcUnifyTypes( PSStlcType a_pstStlcType, size_t a_szTypeSize, const char* a_pcTypeName, PFCompare a_pfnCompare )
{	
	assert( NULL != a_pstStlcType && a_szTypeSize > 0 && NULL != a_pcTypeName && strlen( a_pcTypeName ) > 0 );
	memset( a_pstStlcType, 0, sizeof( SStlcType ) );
	a_pstStlcType->szTypeSize = a_szTypeSize;
	a_pstStlcType->pfnCopy = StlcCopyMemory;
	if( 0 == strcmp( a_pcTypeName, "char" )
		|| 0 == strcmp( a_pcTypeName, "TACHAR" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_SIGNED_CHAR, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareChar;
	}
	else if( 0 == strcmp( a_pcTypeName, "unsigned char" )
		|| 0 == strcmp( a_pcTypeName, "TUCHAR" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_UNSIGNED_CHAR, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareUnsignedChar;
	}
	else if( 0 == strcmp( a_pcTypeName, "short" )
		|| 0 == strcmp( a_pcTypeName, "TSHORT" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_SIGNED_SHORT, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareShort;
	}
	else if( 0 == strcmp( a_pcTypeName, "unsigned short" )
		|| 0 == strcmp( a_pcTypeName, "TUSHORT" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_UNSIGNED_SHORT, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareUnsignedShort;
	}
	else if( 0 == strcmp( a_pcTypeName, "int" )
		|| 0 == strcmp( a_pcTypeName, "TINT" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_SIGNED_INT, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareInt;
	}
	else if( 0 == strcmp( a_pcTypeName, "unsigned int" )
		|| 0 == strcmp( a_pcTypeName, "TUINT" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_UNSIGNED_INT, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareUnsignedInt;
	}
	else if( 0 == strcmp( a_pcTypeName, "long" )
		|| 0 == strcmp( a_pcTypeName, "TLONG" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_SIGNED_LONG, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareLong;
	}
	else if( 0 == strcmp( a_pcTypeName, "unsigned long" )
		|| 0 == strcmp( a_pcTypeName, "TULONG" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_UNSIGNED_LONG, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareUnsignedLong;
	}
	else if( 0 == strcmp( a_pcTypeName, "float" )
		|| 0 == strcmp( a_pcTypeName, "TFLOAT" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_FLOAT, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareFloat;
	}
	else if( 0 == strcmp( a_pcTypeName, "double" )
		|| 0 == strcmp( a_pcTypeName, "TDOUBLE" ) )
	{		
		strncpy( a_pstStlcType->cTypeName, STLCT_DOUBLE, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = ( NULL != a_pfnCompare ) ? a_pfnCompare : StlcCompareDouble;
	}
	else
	{
		strncpy( a_pstStlcType->cTypeName, a_pcTypeName, TYPE_NAME_SIZE );
		a_pstStlcType->pfnCompare = NULL;
	}
}

bool StlcSameType( const SStlcType* a_pstTypeFirst, const SStlcType* a_pstTypeSecond )
{	
	assert( NULL != a_pstTypeFirst && NULL != a_pstTypeSecond );
	if( a_pstTypeFirst->szTypeSize == a_pstTypeSecond->szTypeSize 
		&& a_pstTypeFirst->pfnCompare == a_pstTypeSecond->pfnCompare
		&& 0 == strncmp( a_pstTypeFirst->cTypeName, a_pstTypeSecond->cTypeName, TYPE_NAME_SIZE ) )
	{
		return true;
	}
	return false;
}


